using System;
using System.Collections.Generic;
using System.Runtime.InteropServices;
using CookComputing.XmlRpc;
using Microsoft.SharePoint;
using System.Web;
using System.Diagnostics;

namespace CKS.EBE.API
{
    public class MetaWeblog : XmlRpcService, IMetaWeblogApi
    {
        #region "Structs"
        [StructLayout(LayoutKind.Sequential)]
        public struct BlogDetails
        {
            public string blogid;
            public string url;
            public string blogName;
        }

        [Serializable, StructLayout(LayoutKind.Sequential)]
        public struct CategoryDetails
        {
            public string description;
            public string htmlUrl;
            public string rssUrl;
            public string title;
            public string categoryid;
        }

        [StructLayout(LayoutKind.Sequential), XmlRpcMissingMapping(MappingAction.Ignore)]
        public struct Enclosure
        {
            public int length;
            public string type;
            public string url;
        }

        [StructLayout(LayoutKind.Sequential), XmlRpcMissingMapping(MappingAction.Ignore)]
        public struct MediaObject
        {
            public string name;
            public string type;
            public byte[] bits;
        }

        [Serializable, StructLayout(LayoutKind.Sequential)]
        public struct MediaObjectDetails
        {
            public string url;
        }

        [StructLayout(LayoutKind.Sequential), XmlRpcMissingMapping(MappingAction.Ignore)]
        public struct Post
        {
            [XmlRpcMember(Description = "Required when posting."), XmlRpcMissingMapping(MappingAction.Error)]
            public DateTime dateCreated;
            [XmlRpcMember(Description = "Required when posting."), XmlRpcMissingMapping(MappingAction.Error)]
            public string description;
            [XmlRpcMissingMapping(MappingAction.Error), XmlRpcMember(Description = "Required when posting.")]
            public string title;
            public string[] categories;
            public Enclosure enclosure;
            public string link;
            public string permalink;
            [XmlRpcMember(Description = "Not required when posting. Depending on server may be either string or integer. Use Convert.ToInt32(postid) to treat as integer or Convert.ToString(postid) to treat as string")]
            public object postid;
            public Source source;
            public string userid;
        }

        [StructLayout(LayoutKind.Sequential), XmlRpcMissingMapping(MappingAction.Ignore)]
        public struct Source
        {
            public string name;
            public string url;
        }

        [StructLayout(LayoutKind.Sequential)]
        public struct UserDetails
        {
            public string userid;
            public string firstname;
            public string lastname;
            public string nickname;
            public string email;
            public string url;
        }
        #endregion

        #region IMetaWeblogApi Members

        bool IMetaWeblogApi.deletePost(string appKey, string postid, string username, string password, bool publish)
        {
            SPWeb web = SPContext.Current.Web;
            try
            {
                web.AllowUnsafeUpdates = true;
                SPList postsList = Helper.GetList(web, Localization.BlogList.Posts);
                SPListItem postItem = postsList.GetItemByUniqueId(new Guid(postid));
                postItem.Recycle();
            }
            catch (Exception ex)
            {
                Trace.Write("Error deleting item: " + ex);
                return false;
            }
            finally
            {
                web.AllowUnsafeUpdates = false;
            }

            return true;
        }
        
        bool IMetaWeblogApi.editPost(string postid, string username, string password, Post post, bool publish)
        {
            SPWeb web = SPContext.Current.Web;
            try
            {
                web.AllowUnsafeUpdates = true;
                SPList postsList = Helper.GetList(web, Localization.BlogList.Posts);
                SPListItem postItem = postsList.GetItemByUniqueId(new Guid(postid));

                postItem["Body"] = post.description;
                // Fix for encoding issues with Live Writer
                postItem["Title"] = HttpUtility.HtmlDecode(post.title);

                if (post.dateCreated != DateTime.MinValue)
                {
                    postItem["PublishedDate"] = post.dateCreated;
                }

                if (post.categories != null && post.categories.Length > 0)
                {
                    postItem["Categories"] = BuildCategories(web, post.categories);
                }

                if (publish && postsList.EnableModeration)
                {
                    postItem["_ModerationStatus"] = 0;
                }

                postItem.Update();
            }
            finally
            {
                web.AllowUnsafeUpdates = false;
            }

            return true;
        }

        private static SPFieldLookupValueCollection BuildCategories(SPWeb web, IEnumerable<string> categories)
        {
            SPList oCategoriesList = Helper.GetList(web, Localization.BlogList.Categories);
            var oCats = new SPFieldLookupValueCollection();

            foreach (string category in categories)
            {
                var query = new SPQuery
                                 {
                                     Query = string.Format("<Where><Eq><FieldRef Name='Title'/><Value Type='Text'>{0}</Value></Eq></Where>", category)
                                 };

                SPListItemCollection results = oCategoriesList.GetItems(query);
                if (results.Count > 0)
                {
                    oCats.Add(new SPFieldLookupValue(results[0].ID, category));
                }
            }

            return oCats;
        }

        CategoryDetails[] IMetaWeblogApi.getCategories(string blogid, string username, string password)
        {
            SPWeb web = SPContext.Current.Web;

            SPList oCategories = Helper.GetList(web, Localization.BlogList.Categories);
            var oCats = new List<CategoryDetails>();

            foreach (SPListItem oCat in oCategories.Items)
            {
                var oInfo = new CategoryDetails
                                {
                                    categoryid = oCat.ID.ToString(),
                                    title = oCat.Title,
                                    description = "",
                                    htmlUrl = "",
                                    rssUrl = ""
                                };

                oCats.Add(oInfo);
            }

            return oCats.ToArray();
        }

        Post IMetaWeblogApi.getPost(string postid, string username, string password)
        {
            SPWeb web = SPContext.Current.Web;
            try
            {
                web.AllowUnsafeUpdates = true;
                SPList postsList = Helper.GetList(web, Localization.BlogList.Posts);
                SPListItem postItem = postsList.GetItemByUniqueId(new Guid(postid));

                var post = new Post
                               {
                                   userid = (string) postItem["Author"],
                                   description = (string) postItem["Body"],
                                   title = postItem.Title,
                                   link = postItem.Url,
                                   postid = postItem.UniqueId.ToString(),
                                   dateCreated = (DateTime) postItem["PublishedDate"], 
                                   categories = AddPostItemCategories(postItem)
                               };

                return post;
            }
            catch (Exception ex)
            {
                throw new InvalidOperationException(string.Format("Error getting the post with id {0}: {1}", postid, ex.Message), ex);
            }
            finally
            {
                web.AllowUnsafeUpdates = false;
            }
        }

        Post[] IMetaWeblogApi.getRecentPosts(string blogid, string username, string password, int numberOfPosts)
        {
            SPWeb web = SPContext.Current.Web;
            var oPosts = new List<Post>();

            SPList oList = Helper.GetList(web, Localization.BlogList.Posts);
            var query = new SPQuery
                            {
                                RowLimit = (uint) numberOfPosts,
                                Query = "<OrderBy><FieldRef Name='PublishedDate' Ascending='False' /></OrderBy>"
                            };
            SPListItemCollection postItems = oList.GetItems(query);

            for (int i = 0; i < postItems.Count; i++)
            {
                SPListItem oPost = postItems[i];
                var post = new Post
                               {
                                   userid = (string) oPost["Author"],
                                   description = (string) oPost["Body"],
                                   title = oPost.Title,
                                   link = oPost.Url,
                                   postid = oPost.UniqueId.ToString(),
                                   dateCreated = (DateTime) oPost["PublishedDate"], 
                                   categories = AddPostItemCategories(oPost)
                               };

                oPosts.Add(post);
            }

            return oPosts.ToArray();
        }

        UserDetails IMetaWeblogApi.getUserInfo(string appKey, string username, string password)
        {
            throw new Exception("The method or operation is not implemented.");
        }

        BlogDetails[] IMetaWeblogApi.getUsersBlogs(string appKey, string username, string password)
        {
            SPWeb web = SPContext.Current.Web;
            var blogDetails = new BlogDetails
                                  {
                                      blogid = web.ID.ToString(),
                                      blogName = web.Title,
                                      url = web.Url
                                  };

            return new[] {blogDetails};
        }

        MediaObjectDetails IMetaWeblogApi.newMediaObject(string blogid, string username, string password, MediaObject mediaObject)
        {
            SPWeb web = SPContext.Current.Web;
            try
            {
                web.AllowUnsafeUpdates = true;
                SPList mediaList = Helper.GetList(web, Localization.BlogList.Media);

                string[] arParts = mediaObject.name.Split('/') ;
                SPFolder folder = mediaList.RootFolder;

                int c = 0;
                for (; c < arParts.Length - 1; c++ )
                {
                    SPFolder oSubFolder = null;
                    try
                    {
                        oSubFolder = folder.SubFolders[arParts[c]];
                    } 
                    catch
                    {
                        
                    }
                    if (oSubFolder == null)
                    {
                        oSubFolder = folder.SubFolders.Add(arParts[c]);
                    }

                    folder = oSubFolder;
                }

                SPFileCollection files = folder.Files;
                SPFile newFile = files.Add(string.Format(arParts[c], files.Count), mediaObject.bits, true);

                var details = new MediaObjectDetails
                             {
                                 url = web.Url + ((web.Url.EndsWith("/")) ? "" : "/") + newFile.Url
                             };

                return details;
            }
            catch (Exception ex)
            {
                Trace.Write(ex);
                throw;
            }
            finally
            {
                web.AllowUnsafeUpdates = false;
            }
        }

        string IMetaWeblogApi.newPost(string blogid, string username, string password, Post post, bool publish)
        {
            SPWeb web = SPContext.Current.Web;
            try
            {
                web.AllowUnsafeUpdates = true;
                //SPList oList = Helper.GetListByFolderName(oWeb, Localization.GetListName(Localization.BlogList.Posts, oWeb.Language));
                SPList postsList = Helper.GetList(web, Localization.BlogList.Posts);
                var query = new SPQuery {RowLimit = 0};
                SPListItem newPostItem = postsList.GetItems(query).Add();

                // Fix for encoding issues with Live Writer
                newPostItem["Title"] = HttpUtility.HtmlDecode(post.title);
                newPostItem["Body"] = post.description;
                newPostItem["PublishedDate"] = (post.dateCreated == DateTime.MinValue) ? DateTime.Now : post.dateCreated;
                
                if (publish && postsList.EnableModeration)
                {
                    newPostItem["_ModerationStatus"] = 0;
                }

                try
                {
                    if (post.categories != null && post.categories.Length > 0)
                    {
                        newPostItem["Categories"] = BuildCategories(web, post.categories);
                    }
                }
                catch (Exception ex)
                {
                    Trace.WriteLine("Error during processing of Categories: " + ex);
                    throw new InvalidOperationException("Error during processing of Categories: " + ex.Message, ex);
                }

                newPostItem.Update();
                return newPostItem.UniqueId.ToString();
            }
            catch (Exception ex)
            {
                Trace.Write(ex);
                throw;
            }
            finally
            {
                web.AllowUnsafeUpdates = false;
            }
        }

        #endregion

        /// <summary>
        /// read categories from listitem, and add them to the post
        /// </summary>
        /// <param name="postItem"></param>
        /// <returns></returns>
        private static string[] AddPostItemCategories(SPItem postItem)
        {
            var arCats = new List<string>();
            var oCats = (SPFieldLookupValueCollection)postItem["Categories"];
            if (oCats == null || oCats.Count <= 0) return null;

            foreach (SPFieldLookupValue lv in oCats)
            {
                arCats.Add(lv.LookupValue);
            }
            return arCats.ToArray();
        }
    }
}